import { ethers } from "ethers";
import {
  API_CONFIG,
  USDT_CONTRACT_ADDRESS,
  getNetwork
 } from "./config";
import { userStore } from "../../stores/modules/user";
import moment from "moment";
import { PIZZA as PIZZAI ,IBEP20,PIZZA__factory} from "./typechain-types/index";
import { PizzaSpace } from "./typechain-types/contracts/pizzaspace_nft.sol";

 
export class Contract {
  static address = null;
  static provider: ethers.BrowserProvider;
  static wallet = null;
  static contract = null;

  static init() {
    this.setProvider();
  }

  static USDT = async ():Promise<IBEP20> => {
    const contract = new ethers.Contract(
      USDT_CONTRACT_ADDRESS,
      API_CONFIG.USDT,
      this.provider
    );
    return contract.connect(await this.provider!.getSigner()) as IBEP20;
  };

  static PIZZA = async (): Promise<PIZZAI> => {
    const contract = new ethers.Contract(
      getNetwork().pizzaAddress,
      PIZZA__factory.abi,
      this.provider
    );
    

    return contract.connect(await this.provider!.getSigner()) as PIZZAI;
  };

  static PIZZANFT = async (): Promise<PizzaSpace> => {
    const contract = new ethers.Contract(
      getNetwork().nftAddress,
      API_CONFIG.ERC721,
      this.provider
    );
    return contract.connect(await this.provider!.getSigner()) as PizzaSpace;
  };
  // ----------------------------------------------------------------------------------------
  static async transferUSDT(account: string, amount: string) {
    const contract = new ethers.Contract(
      USDT_CONTRACT_ADDRESS,
      API_CONFIG.USDT,
      this.provider
    );
    const singer = contract.connect(await this.provider.getSigner());
    return new Promise(resolve => {
      (singer as any)
        .transfer(account, ethers.parseUnits(amount, 18))
        .then(() => {
          resolve({ message: "成功", code: 200 });
        })
        .catch(() => {
          resolve({ message: "失败", code: 500 });
        });
    });
  }

  static async signMessage() {
    let today = moment(moment().format("YYYY-MM-DD")).unix();
    const sign = await (window as any).ethereum.request({
      method: "personal_sign",
      params: [
        "welcome pizza at " + today,
        (window as any).ethereum.selectedAddress
      ]
    });

    userStore().updateSign(sign);
  }

  static setProvider() {
    if ((window as any).ethereum == null) {
      console.log("MetaMask not installed; using read-only defaults");
      // this.provider = ethers.getDefaultProvider()
    } else {
      this.provider = new ethers.BrowserProvider((window as any).ethereum);
    }
    this.address = (window as any).ethereum.selectedAddress;
  }

  static async balance(contract_address) {
    const contract = await new ethers.Contract(
      contract_address,
      API_CONFIG.USDT,
      this.provider
    );
    const bal = await contract.balanceOf(this.address);
    const decimal = await contract.decimals();
    return ethers.formatUnits(bal, decimal);
  }

  static async ownerOf(contract_address, tokenID) {
    const contract = await new ethers.Contract(
      contract_address,
      API_CONFIG.ERC721,
      this.provider
    );

    const bal = await contract.ownerOf(tokenID);
    return bal;
  }

  static async ERC721BalanceOf(contract_address: string) {
    const contract = await new ethers.Contract(
      contract_address,
      API_CONFIG.ERC721,
      this.provider
    );
    const count = await contract.balanceOf(this.address);
    return count;
  }

  static async pledgeNFT(tokenIDs: ethers.BigNumberish[]) {
    return new Promise(async (resolve, reject) => {
    
        const nft = await this.PIZZANFT();
        const hasApprove = await nft.isApprovedForAll(this.address,getNetwork().pizzaAddress).catch((err)=>reject(err))
        if (!hasApprove) {
            nft.setApprovalForAll(getNetwork().pizzaAddress, true).then(async (res)=>{
          (await this.PIZZA()).pledgeNFT(tokenIDs).then((res)=>resolve(res)).catch((err)=>reject(err))
          }).catch((err)=>reject(err))
        }

        (await this.PIZZA()).pledgeNFT(tokenIDs).then((res)=>resolve(res)).catch((err)=>reject(err))
      
    });
  }

  static async usdtApproval(/*_contract_address = USDT_CONTRACT_ADDRESS*/) {
    return new Promise(async (resolve, reject) => {
        (await this.USDT()).allowance(this.address, getNetwork().pizzaAddress).then(async (res) => {
          console.warn("授权金额",Number(ethers.formatEther(res)))
            if (Number(ethers.formatEther(res)) <= Number(1000000000)) {
                 (await this.USDT()).approve(getNetwork().pizzaAddress, ethers.MaxUint256).then(() => {
                    console.log("approve success")
                    resolve(true)
                }).catch((error) => {
                    console.warn("approve失敗", error)
                    reject(error)
                    // If the request fails, the Promise will reject with an error.
                });
            } else {
                resolve(true)
                console.warn("请求allowance 3")
            }
        }).catch((e) => {
            console.warn(e)
        })
    })
}
  static async recharge(amount:string) {
    return new Promise(async (resolve) => {
        this.usdtApproval().then(async () => {
          console.log(this.address);
            (await this.USDT()).balanceOf(this.address).then(async res => {
              console.log("余额",Number(ethers.formatEther(res)),"金额",Number(amount))
                if (Number(ethers.formatEther(res)) >= Number(amount)) {
                   var pizza = await this.PIZZA();
                   console.warn(amount);
                    (pizza).rechange(ethers.parseEther(amount)).then(() => {
                        resolve({ message:"rechargeSuccessful", code: 200 })
                    }).catch((e) => {
                        console.warn(e)
                        resolve({ message:"rechargeFailed", code: 500 })
                    })
                } else {
                    resolve({ message:"balanceInsufficient", code: 500 })
                }
            }).catch((err)=>{
                console.log("檢查USDT餘額是否足夠出錯",err)
                resolve({ message:("checkingWhetherUSDT"), code: 500 })
            })
        }).catch((err)=>{
            console.log("usdtApproval reject",err)
            resolve({ message:("usdtApprovalReject"), code: 500 })
        })
    })
}
}


